/*	____________________________________________________________________________

	    Semantics and Coding Component Implementation for the PhiMP Compiler
	____________________________________________________________________________  */

#include <iostream>
#include <fstream>
#include <sstream>
#include <math.h>
using namespace std;

extern ifstream sourceFile;
extern ofstream outFile, listFile;

#include "parse.h"   // Scanner class definition
#include "scan.h"   // Scanner class definition
#include "code.h"   // CodeGen class definition

extern Scanner scan; // global Scanner object declared in micro.cpp
extern Parser parse; // global scanner declared in PhiMP.cpp

// *******************
// **  Constructor  **
// *******************

CodeGen::CodeGen()
{
	maxTemp = 0;
}

// *******************************
// ** Private Member Functions  **
// *******************************

void CodeGen::CheckId(ExprRec& e)
{
	//cout << "We are in the CheckId function, biznatch." << endl;
	if (!LookUp(e))  // variable not declared yet
		parse.SyntaxError("Variable '" + e.name + "' not declared yet");

}

void CodeGen::CreateVar(ExprRec& e)
{
	if (!LookUp(e))
	{
		//cout << e.name << endl;
		Enter(e);
	}
	else
		parse.SyntaxError("Variable " + e.name + " already exists");
	
}

void CodeGen::CreateFunction(string name, string& EndFuncAddress)
{
	//EndFuncAddress = GetTemp();

	Generate("LABEL		", name, "");
}

void CodeGen::FunctionCall(string name, string EndFuncAddress)
{
	Generate("JMP		", name, "");
	Generate("LABEL		", EndFuncAddress, "");

}

void CodeGen::EndFunctionCall(string EndFuncAddress)
{
	Generate("JMP		", EndFuncAddress, "");
}


void CodeGen::StartForLoop(ExprRec start, ExprRec end, ExprRec& startLoop, ExprRec& endLoop, int forCount)
{
	string str1, str2, str3;
	startLoop.dataType = ADDRESS;
	endLoop.dataType = ADDRESS;
	Enter(startLoop);
	Enter(endLoop);

	ExtractExpr(start, str1);
	ExtractExpr(end, str2);

	//FloatToAlpha(start.val, str1);
	//FloatToAlpha(end.val, str2);
	IntToAlpha(forCount, str3);
	Generate("LD		", "R0", str1);
	Generate("STO		", "R0", "+" + str3 + "(R10)");

	Generate("LABEL		", startLoop.name, "");

	Generate("LD		", "R0", str2);
	Generate("LD		", "R1", "+" + str3 + "(R10)");
	Generate("IC		", "R0", "R1");
	Generate("JLE		", endLoop.name, "");
}

void CodeGen::EndForLoop(ExprRec start, ExprRec step, ExprRec startLoop, ExprRec endLoop, int forCount)
{
	string str1, str2;
	//FloatToAlpha(start.val, str1);
	IntToAlpha(forCount, str2);

	ExtractExpr(step, str1);

	Generate("LD		", "R0", "+" + str2 + "(R10)");
	Generate("IA		", "R0", str1);
	Generate("STO		", "R0", "+" + str2 + "(R10)");
	Generate("JMP		", startLoop.name, "");
	Generate("LABEL		", endLoop.name, "");
}

void CodeGen::StartIfStatement(ExprRec BoolExpression, ExprRec& NextElifOrElseAddress)
{
	string str1, str2;

	ExtractExpr(BoolExpression, str1);

	/* if(str1[0] != '#')
	{
		Generate("LD		", "R0", str1);
		Generate("IC		", "R0", "#1");
		Generate("JNE		", NextElifOrElseAddress.name, "");
	}*/


}

void CodeGen::EndIfStatement(ExprRec NextElifOrElseAddress)
{

	Generate("LABEL		", NextElifOrElseAddress.name, "");
}


void CodeGen::ElseStatement(ExprRec NextElifOrElseAddress, ExprRec EndElseAddr)
{

	Generate("JMP		", EndElseAddr.name, "");
	Generate("LABEL		", NextElifOrElseAddress.name, "");

}

void CodeGen::EndElseStatement(ExprRec EndElseAddress)
{
	Generate("LABEL		", EndElseAddress.name, "");
}

void CodeGen::ElifStatement(ExprRec BoolExpression, ExprRec& NextElifOrElseAddress)
{
	string str1;

	ExtractExpr(BoolExpression, str1);

	Generate("LABEL		", NextElifOrElseAddress.name);
	Enter(NextElifOrElseAddress);
	Generate("IC		", str1, "#1");
	Generate("JNE		", NextElifOrElseAddress.name, "");

}


void CodeGen::Negate(ExprRec& e)
{
	ExprRec zeroOperand;
	ExprRec oldE;
	OpRec op;
	
	zeroOperand.kind = LITERAL_EXPR; 
	zeroOperand.val = 0;
	zeroOperand.name = "0";
	zeroOperand.dataType = e.dataType;
	op.op = MINUS;

	if( e.kind == LITERAL_EXPR )
	{
		oldE.kind = LITERAL_EXPR;
		oldE.dataType = e.dataType;
		oldE.val = e.val;

		e.kind = ID_EXPR; // If it's literal... it's NOT going to work... convert it to an ID_EXPR yo
		CreateVar(e);	
		Assign(e, oldE);	// Assign it's old value
	}

	

	if( e.dataType == REAL )
	{
		//parse.Warning("Negate does not work!");
		//Generate("FN		", str1);

		GenInfix(zeroOperand, op, e, oldE);
		Assign( e, oldE);
	}
	else if( e.dataType == INT )
	{	
		GenInfix(zeroOperand, op, e, oldE);
		Assign(e, oldE); // put the negative value in
		
		//parse.Warning("Negate does not work!");
		//Generate("IN		", str1); // Does not work!!
	}
	else
		parse.SyntaxError("Cannot negate that datatype!");
}	

void CodeGen::Enter(ExprRec& e)
{
	string str;

	switch( e.dataType )
	{
	case INT:
		intTable.push_back(e);
		break;
	case REAL:
		realTable.push_back(e);
		break;
	case CHAR:
		charTable.push_back(e);
		break;
	case BOOL:
		boolTable.push_back(e);
		break;
	case ADDRESS:
		IntToAlpha(addressTable.size()+1, str);
		e.name = "ADDR"+str;
		addressTable.push_back(e);
		break;
	// There are technically no string variables so I took this out for now
	/*
	case STRING:
		stringTable.push_back(s);
		break;
	*/
	}
}

void CodeGen::ExtractExpr(ExprRec e, string& s, int offset)
{
	string t;
	string regNum = "";
	int k, n;

	n = 0;

	switch (e.kind)
	{
	case ID_EXPR:
	case TEMP_EXPR:  // operand form: +k(R15)
		s = e.name;
		n = 0;
		switch(e.dataType)
		{
			case INT:
 				while(intTable[n].name != s) n++;
				k = 2 * n;  // offset: 2 bytes per INT variable
				regNum = "(R10)";
				break;
			case REAL:
				while(realTable[n].name != s) n++;
				k = 4 * n;  // offset: 4 bytes per REAL variable
				regNum = "(R11)";
				break;
			case CHAR:
				while(charTable[n].name != s) n++;
				k = n;		// offset: 1 byte per CHAR variable
				regNum = "(R13)";
				break;
			case BOOL:
				while(boolTable[n].name != s) n++;
				k = n;		// offset: 1 byte per BOOL variable
				regNum = "(R14)";
				break;
				// There are technically no string variables so I took this out for now
			/*case STRING:
				while(stringTable[n] != s) n=n+length(stringTable[n]);
				k = n;
				IntToAlpha(k, t);
				s = "+" + t + "(R15)";
				break;*/
		}
		IntToAlpha(k+offset, t);
		s = "+" + t + regNum;
		break;
	case LITERAL_EXPR:
		if (e.dataType == INT || e.dataType == BOOL || e.dataType == CHAR)
		{
			IntToAlpha(int(e.val), t);
			s = "#" + t;
		}
		else if (e.dataType == REAL) // REALS must be defined in the data area
		{
			ostringstream oss;

			oss << e.val;
			e.name = "r"+oss.str();

			while(realTable[n].name != e.name)
			{
				n++;
				if(n >= (int)realTable.size())
				{
					CreateVar(e);
					break;
				}
			}
			k = 4 * n;  // offset: 4 bytes per REAL variable
			IntToAlpha(k+offset, t);
			s = "+" + t + "(R11)";
		}
		break;
	}
}

void CodeGen::GenModCode(ExprRec e1, ExprRec e2)
{
	string opnd1;
	string opnd2;

	ExtractExpr(e1, opnd1);
	ExtractExpr(e2, opnd2);

	Generate("ID		", "R0", opnd2);
	Generate("IM		", "R0", opnd2);
	Generate("STO		", "R0", "R1");
	Generate("LD		", "R0", opnd1);
	Generate("IS		", "R0", "R1");
}

void CodeGen::GenPowCode(ExprRec e1, ExprRec e2)
{
	string opnd1;
	string opnd2;
	ExprRec startAddr;
	ExprRec endAddr;

	ExprRec start;
	ExprRec step;
	step.dataType = INT;
	step.kind = LITERAL_EXPR;
	step.val = 1;
	start.name = "POWSTEP";
	start.dataType = INT;
	start.kind = LITERAL_EXPR;
	start.val = 0;
	start.name = "POW1";
	e2.name = "POW2";

	ExtractExpr( e1, opnd1);

	StartForLoop(start, e2, startAddr, endAddr, 0);
	if( e1.dataType == INT )
		Generate("IM		", opnd1, opnd1);
	else if( e1.dataType == REAL )
		Generate("FM		", opnd1, opnd1);
	EndForLoop( start, step, startAddr, endAddr, 0);

	/*Generate("LD		", "R1", opnd2);
	Generate("IC		", "R1", "#0");
	Generate("JNE		", "+6", "");
	Generate("LD		", "R0", "#1");
	Generate("JMP		", "+18", "");
	Generate("IC		", "R1", "#1");
	Generate("JEQ		", "+8", "");
	Generate("IM		", "R0", opnd1);
	Generate("IS		", "R1", "#1");
	Generate("JMP		", "-12", "");*/
}

void CodeGen::GenBoolOps(OpRec o, ExprRec e1, ExprRec e2, bool isIf, ExprRec NextAddress)
{
	string opnd1;
	string opnd2;

	ExtractExpr( e1, opnd1 );
	ExtractExpr( e2, opnd2 );

	if(e1.dataType != e2.dataType)
		parse.SyntaxError("Data types do not match");
	else
	{
		if(e1.dataType == INT)
		{
			Generate("LD		", "R0", opnd1);
			Generate("IC		", "R0", opnd2);
		}
		else if(e1.dataType == REAL)
		{
			Generate("LD		", "R0", opnd1);
			Generate("FC		", "R0", opnd2);
		}

		Generate("LD		", "R0", "#1");
		switch(o.op)							/* ****** Still need to figure out jump addresses!  ********/
		{
		case(LT):								// If less than then
			if(!isIf)
				NextAddress.name = "+4";	// Only temporary..not passed by Address
			Generate("JGE		", NextAddress.name, "");	// Jumps to address of } for if statement if greater than or equal to
			Generate("LD		", "R0", "#0");
			break;
		case(LE):								// If less then or equal to then
			if(!isIf)
				NextAddress.name = "+4";
			Generate("JGT		", NextAddress.name, "");
			Generate("LD		", "R0", "#0");
			break;
		case(EQ):								// If equal to then
			if(!isIf)
				NextAddress.name = "+4";
			Generate("JNE		", NextAddress.name, "");
			Generate("LD		", "R0", "#0");
			break;
		case(NE):								// If not equal to then
			if(!isIf)
				NextAddress.name = "+4";
			Generate("JEQ		", NextAddress.name, "");
			Generate("LD		", "R0", "#0");
			break;
		case(GE):								// If greater or equal to then
			if(!isIf)
				NextAddress.name = "+4";
			Generate("JLT		", NextAddress.name, "");
			Generate("LD		", "R0", "#0");
			break;
		case(GT):								// If greater than then
			if(!isIf)
				NextAddress.name = "+4";
			Generate("JLE		", NextAddress.name, "");
			Generate("LD		", "R0", "#0");
			break;
		}
	}

}



string CodeGen::ExtractOp(OpRec o, ExprRec e1, ExprRec e2)
{
	if (e1.dataType == INT && e2.dataType == INT)
		if (o.op == PLUS)
			return "IA        ";
		else if (o.op == MINUS)
			return "IS        ";
		else if (o.op == MULT)
			return "IM        ";
		else if (o.op == INT_DIV)
			return "ID        ";
		else
			parse.SyntaxError();

	else if (e1.dataType == REAL || e2.dataType == REAL)
	{
		if (o.op == INT_MOD || o.op == INT_DIV || o.op == POWER)
			parse.SyntaxError("Numbers must both be integers");

		if (e1.dataType == INT)
			IntToReal(e1);
		else if (e2.dataType == INT)
			IntToReal(e2);

		if (o.op == PLUS)
			return "FA        ";
		else if (o.op == MINUS)
			return "FS        ";
		else if (o.op == MULT)
			return "FM        ";
		else if (o.op == DIV)
			return "FD        ";
		else
			parse.SyntaxError();
	}
	else
		parse.SyntaxError();
		return "";
}

void CodeGen::GenOtherOps(OpRec o, ExprRec e1, ExprRec e2)
{
	//if (e1.val < 0 || e2.val < 0)
	//	parse.SyntaxError("Numbers must be positive");
	
	if (o.op == INT_MOD)
		GenModCode(e1, e2);
	else
		GenPowCode(e1, e2);
}



void CodeGen::Generate(string s1, string s2, string s3)
{
	listFile.width(20);
	listFile << ' ' << s1;
	outFile << s1;
	if (s2.length() > 0)
	{
		listFile << s2;
		outFile << s2;
		if (s3.length() > 0)
		{
			listFile << ',' << s3;
			outFile << ',' << s3;
		}
	}
	listFile << endl;
	outFile << endl;
}

void CodeGen::GetTemp(ExprRec& result)
{
	string s;

	result.name = "Temp&";
	IntToAlpha(++maxTemp, s);
	result.name += s;
	result.kind = TEMP_EXPR;
	if(!LookUp(result))
		Enter(result);
}

void CodeGen::IntToReal(ExprRec& e)
{
	string s;
	e.dataType = REAL;
}

void CodeGen::FloatToAlpha(float val, string& str)
{
	ostringstream ss;

	ss << val;

	str = ss.str();
}

void CodeGen::IntToAlpha(int val, string& str)
{
	int k;
	char temp;
	bool negative = false;

	str = "";
	if (val == 0) str = "0";
	else if (val < 0)
	{
		negative = true;
		val = -val;
	}
	while (val > 0)
	{
		str.append(1, (char)(val % 10 + (int)'0'));
		val /= 10;
	}

	if(negative) str.append("-");

	k = int(str.length());
	for (int i = 0; i < k/2; i++)
	{
		temp = str[i];
		str[i] = str[k-i-1];
		str[k-i-1] = temp;
	}
}

bool CodeGen::LookUp(ExprRec& e)
{
	//cout << "\n\n" << endl;
	//cout << "kind: " << e.kind << "\ndataType" << e.dataType << "\nname: " << e.name << "\nval: " << e.val << endl;
	for (unsigned i = 0; i < intTable.size(); i++)
	{
		//cout << "\n" << i << " value in intTable: " << intTable[i].name << endl;
		if (intTable[i].name == e.name)
		{
			e.dataType = INT;
			return true;
		}
	}
	for (unsigned i = 0; i < charTable.size(); i++)
	{
		if (charTable[i].name == e.name)
		{
			e.dataType = CHAR;
			return true;
		}
	}
	for (unsigned i = 0; i < realTable.size(); i++)
	{
		if (realTable[i].name == e.name)
		{
			e.dataType = REAL;
			return true;
		}
	}
	for (unsigned i = 0; i < boolTable.size(); i++)
	{
		if (boolTable[i].name == e.name)
		{
			e.dataType = BOOL;
			return true;
		}
	}

	// There are technically no string variables so I took this out for now
	/*  
	for (unsigned i = 0; i < stringTable.size(); i++)
	{
		if (stringTable[i].name == s)
		{
			e.dataType = STRING;
			return true;
		}
	}
	*/

	return false;
}

// ******************************
// ** Public Member Functions  **
// ******************************

void CodeGen::Assign(ExprRec target, ExprRec source)
{
	string s;

	if (target.dataType == source.dataType)
	{
		ExtractExpr(source, s);
		Generate("LD        ", "R0", s);
		if( source.dataType == REAL )
		{
			ExtractExpr(target, s, 2);
			Generate("LD		", "R1", s);
		}

		ExtractExpr(target, s);
		Generate("STO       ", "R0", s);
		if( target.dataType == REAL)
		{
			ExtractExpr(target, s, 2);
			Generate("STO		", "R1", s);
		}
	}
	else
		parse.SyntaxError("Type mismatch");

}

void CodeGen::Finish()
{
	string s;
	int skip;

	listFile.width(6);
	listFile << ++scan.lineNumber << "  " << scan.lineBuffer << endl;

	Generate("HALT      ", "", "");


	Generate("","","");
	Generate("% DATA AREA %", "", "");
	Generate("% --------- %", "", "");
	Generate("LABEL     ", "INTS", "");
	skip = int(2 * intTable.size()+2);
	IntToAlpha(skip, s);
	Generate("SKIP      ", s, "");

	Generate("LABEL     ", "FLOATS", "");
	skip = 0;
	for( int i = 0; i < (int)realTable.size(); i++ )
	{
		if( realTable[i].kind == LITERAL_EXPR )
		{
			if( skip > 0)
			{
				FloatToAlpha((float)skip, s);
				Generate("SKIP		", s, ""); // Dump the variables storage space
				skip = 0;
			}
			FloatToAlpha(realTable[i].val, s);
			Generate("REAL		", s, "");			
		}
		else
			skip += 4;
	}
	if( skip > 0 )
	{
		FloatToAlpha((float)skip, s);
		Generate("SKIP		", s, "");
	}

	Generate("LABEL     ", "CHARS", "");
	skip = int(charTable.size());
	IntToAlpha(skip, s);
	if( skip > 0)
		Generate("SKIP		", s, "");

	Generate("LABEL     ", "BOOLS", "");
	skip = int(boolTable.size() + 2);
	IntToAlpha(skip, s);
	Generate("SKIP		", s, "");

	//////////////////////////////////////
	// Write the STRINGS section of the data area
	//////////////////////////////////////
	Generate("LABEL     ","STRINGS","");

	// Process escape characters in all of our strings
	for( int i = 0; i < (int)stringTable.size(); i++ )
	{
		string newString = "";

		for( int j = 0; j < (int)stringTable[i].name.size(); j++ )
		{
			if( stringTable[i].name.at(j) == ':' || stringTable[i].name.at(j) == '"' )
				newString += ":";
			if( stringTable[i].name.at(j) == '\\' )
			{
				if( (int)stringTable[i].name.length() >= j+1 )
				{
					char nextChar = stringTable[i].name.at(j+1);
					if( nextChar == 'n' )
					{
						newString += ":010:013";
						j+=1;
						continue;
					}
					else if( nextChar == 't' )
					{
						newString += ":009";
						j+=1;
						continue;
					}
					else if( nextChar == '\\' )
					{
						newString += "\\";
						j+=1;
						continue;
					}
					else if( nextChar == '"' )
					{
						newString += ":\"";
						j+=1;
						continue;
					}
					else if( nextChar == '0' )
					{
						newString += ":000";
						j+=1;
						continue;
					}
					else if( isalnum(nextChar) )
					{
						newString += ":";
						continue;
					}
				}
			}
			newString.push_back(stringTable[i].name.at(j));
		}
		stringTable[i].name = newString;
	}

	// Add them to our data area
	for( unsigned int i = 0; i < stringTable.size(); i++ )
	{
		Generate("STRING    ", "\"" + stringTable[i].name + "\"","");
	}

	outFile.close();
	listFile << endl << endl;
	listFile << " _____________________________________________\n";
	listFile << " <><><><>   S Y M B O L   T A B L E   <><><><>\n"
		<< endl;
	listFile << " Relative" << endl;
	listFile << " Address      Identifier" << endl;
	listFile << " --------     --------------------------------" 
		<< endl;
	DisplayIdents();
	listFile << " _____________________________________________" 
		<< endl;
	listFile << endl;
	listFile << " Normal successful compilation." << endl;
	listFile.close();
}

void CodeGen::DisplayIdents()
{
	int totalSize = 0;

	for (unsigned i = 0; i < intTable.size(); i++)
	{
		listFile.width(7);
		listFile << 2*i << "       " << intTable[i].name << endl;
	}

	totalSize = 2 * (int)intTable.size();

	for (unsigned i = 0; i < realTable.size(); i++)
	{
		listFile.width(7);
		listFile << totalSize + 4*i << "       " << realTable[i].name << endl;
	}

	totalSize = totalSize + 4 * (int)realTable.size();

	for (unsigned i = 0; i < charTable.size(); i++)
	{
		listFile.width(7);
		listFile << i + totalSize << "       " << charTable[i].name << endl;
	}

	totalSize = totalSize + (int)charTable.size();
	
	for (unsigned i = 0; i < boolTable.size(); i++)
	{
		listFile.width(7);
		listFile << i + totalSize<< "       " << boolTable[i].name << endl;
	}

}


void CodeGen::GenInfix(ExprRec e1, OpRec op, ExprRec e2, ExprRec& e)
{
	string opnd1, opnd2, opnd3;

	if (e1.dataType == INT && e2.dataType == INT)	// If both expressions evaluate to an INT, then the result is an INT
		e.dataType = INT;
	else if(e1.dataType == REAL || e2.dataType == REAL)  // If either one of the expressions evaluate to a REAL, then the result must be REAL
	{
		e.dataType = REAL;
		if(e1.dataType == INT)
			IntToReal(e1);
		else if (e2.dataType == INT)
			IntToReal(e2);
	}

	if (e1.kind == LITERAL_EXPR && e2.kind == LITERAL_EXPR)
	{
		e.kind = LITERAL_EXPR;

		switch (op.op)
		{
			case PLUS:
				e.val = e1.val + e2.val;
				break;
			case MINUS:
				e.val = e1.val - e2.val;
				break;
			case MULT:
				e.val = e1.val * e2.val;
				break;
			case DIV:
				e.val = e1.val / e2.val;
				break;
			case INT_DIV:
				if ((e1.dataType == INT) && (e2.dataType == INT))
					e.val = (float)((int)(e1.val / e2.val));
				else
					parse.SyntaxError("Type mismatch");
				break;
			case INT_MOD:
				if ((e1.dataType == INT) && (e2.dataType == INT))
					e.val = (float)((int)(e1.val) % (int)(e2.val));
				else
					parse.SyntaxError("Type mismatch");
				break;
			case POWER:
				 if ((e1.dataType == INT) && (e2.dataType == INT))
					e.val = (float)((int)(pow(e1.val, e2.val)));
				else
					parse.SyntaxError("Type mismatch");
				break;
		}
	}
	else
	{
		GetTemp(e);

		ExtractExpr(e1, opnd1);
		Generate("LD        ", "R0", opnd1);
		if( e.dataType == REAL )
		{
			ExtractExpr( e1, opnd1, 2 );
			Generate("LD		", "R1", opnd1);
		}

		ExtractExpr(e2, opnd2);
		if(op.op == INT_MOD || op.op == POWER)
			GenOtherOps(op, e1, e2);
		else
		{
			Generate(ExtractOp(op, e1, e2), "R0", opnd2);
		}
		ExtractExpr(e, opnd3);
		Generate("STO       ", "R0", opnd3);
		if( e.dataType == REAL )
		{
			ExtractExpr(e, opnd3, 2);
			Generate("STO		", "R1", opnd3);
		}
	}
}

void CodeGen::BoolGenInfix(ExprRec e1, OpRec op, ExprRec e2, ExprRec& e, bool isIf, ExprRec NextAddress)
{
	string opnd1, opnd2, opnd3;

	if (e1.dataType == INT && e2.dataType == INT)	// If both expressions evaluate to an INT, then the result is an INT
		e.dataType = INT;
	else if(e1.dataType == REAL || e2.dataType == REAL)  // If either one of the expressions evaluate to a REAL, then the result must be REAL
	{
		e.dataType = REAL;
		if(e1.dataType == INT)
			IntToReal(e1);
		else if (e2.dataType == INT)
			IntToReal(e2);
	}

	if (e1.kind == LITERAL_EXPR && e2.kind == LITERAL_EXPR)
	{
		e.kind = LITERAL_EXPR;

		switch (op.op)
		{
			case LT:
				e.dataType = BOOL;
				e.val = e1.val < e2.val;
				break;
			case LE:
				e.dataType = BOOL;
				e.val = e1.val <= e2.val;
				break;
			case EQ:
				e.dataType = BOOL;
				e.val = e1.val == e2.val;
				break;
			case NE:
				e.dataType = BOOL;
				e.val = e1.val != e2.val;
				break;
			case GE:
				e.dataType = BOOL;
				e.val = e1.val >= e2.val;
				break;
			case GT:
				e.dataType = BOOL;
				e.val = e1.val > e2.val;
				break;
		}
	}
	else
	{
		GetTemp(e);

		ExtractExpr(e1, opnd1);
		Generate("LD        ", "R0", opnd1);
		if( e.dataType == REAL )
		{
			ExtractExpr( e1, opnd1, 2 );
			Generate("LD		", "R1", opnd1);
		}

		ExtractExpr(e2, opnd2);
		if(op.op == LT || op.op == LE || op.op == EQ || op.op == NE || op.op == GE || op.op == GT)
		{
			GenBoolOps(op, e1, e2, isIf, NextAddress);
		}
		else
			parse.SyntaxError("Wrong relational operator found!");
		ExtractExpr(e, opnd3);
		Generate("STO       ", "R0", opnd3);
		if( e.dataType == REAL )
		{
			ExtractExpr(e, opnd3, 2);
			Generate("STO		", "R1", opnd3);
		}
	}
}

void CodeGen::NewLine()
{
	Generate("WRNL      ", "", "");
}

void CodeGen::ProcessId(ExprRec& e)
{
	e.kind = ID_EXPR;
	e.name = scan.tokenBuffer;
	CreateVar(e);
}

void CodeGen::ProcessLiteral(ExprRec& e)
{
	e.kind = LITERAL_EXPR;
	
	istringstream iss(scan.tokenBuffer);
	ostringstream oss;
	string str1;

	switch( e.dataType )
	{
	case INT:
		e.val = (float)atoi(scan.tokenBuffer.data());
		break;
	case REAL:
		// Grab the float from the tokenBuffer
		e.kind = LITERAL_EXPR;
		iss >> e.val;

		ExtractExpr(e, str1); // This will create it if need be
		break;

	case CHAR:
		e.val = (float)(int)scan.tokenBuffer[0];
		break;

	case BOOL:
		if(scan.tokenBuffer == "true")
			e.val = 1;
		else if(scan.tokenBuffer == "false")
			e.val = 0;
		break;

	case STRING: 
		e.name = scan.tokenBuffer;
		//cout << "ProcessLiteral is STRING: " << scan.tokenBuffer << endl;
		break;

	}
}

void CodeGen::ProcessOp(OpRec& o)
{
	if(scan.tokenBuffer == "+")
		o.op = PLUS;
	else if(scan.tokenBuffer == "-")
		o.op = MINUS;
	else if(scan.tokenBuffer == "*")
		o.op = MULT;
	else if(scan.tokenBuffer == "/")
		o.op = DIV;
	else if(scan.tokenBuffer == "DIV")
		o.op = INT_DIV;
	else if(scan.tokenBuffer == "MOD")
		o.op = INT_MOD;
	else if(scan.tokenBuffer == "^")
		o.op = POWER;
	else if(scan.tokenBuffer == "<")
		o.op = LT;
	else if(scan.tokenBuffer == "<=")
		o.op = LE;
	else if(scan.tokenBuffer == "==")
		o.op = EQ;
	else if(scan.tokenBuffer == ">")
		o.op = GT;
	else if(scan.tokenBuffer == ">=")
		o.op = GE;
	else if(scan.tokenBuffer == "~=")
		o.op = NE;
}

void CodeGen::ReadId(ExprRec inVar)
{
	string s;

	ExtractExpr(inVar, s);

	switch(inVar.dataType)
	{
	case(INT):
		Generate("RDI       ", s, "");
		break;
	case(REAL):
		Generate("RDF		", s, "");
		break;
	case(CHAR):
		Generate("RDCH		", s, "");
		break;
	// There are technically no string variables so I took this out for now
	/*
	case(STRING):
		Generate("RDST		", s, "");
		break;
	*/
	}
}

void CodeGen::Start()
{
	Generate("LDA		", "R10", "INTS");
	Generate("LDA		", "R11", "FLOATS");
	Generate("LDA		", "R13", "CHARS");
	Generate("LDA		", "R14", "BOOLS");
	Generate("LDA		", "R15", "STRINGS");
}

void CodeGen::WriteExpr(ExprRec outExpr)
{
	string s;

	if( outExpr.dataType == STRING )
	{
		WriteString(outExpr);
		return;
	}

	ExtractExpr(outExpr, s);

	switch(outExpr.dataType)
	{
	case(INT):
		Generate("WRI       ", s, "");
		break;
	case(REAL):
		Generate("WRF		", s, ""); // Write it!
		break;
	case(CHAR):
		Generate("WRCH		", s, "");
		break;
	case(BOOL):
		Generate("WRI		", s, "");
	// There are technically no string variables so I took this out for now
	/*
	case(STRING):
		Generate("WRST		", s, "");
		break;
	*/
	}
}

// Print whatever is in the token buffer
void CodeGen::WriteString(ExprRec e)
{
	string s;

	// Write the string
	IntToAlpha(stringAddress, s);
	Generate("WRST      ", "+" + s + "(R15)","");

	// Strings stop on a null character
	stringTable.push_back(e);
	stringAddress += int(e.name.length()+1);
	
	if( stringAddress % 2 != 0 ) // The number of bytes MUST be even
		stringAddress++;
}